package jp.ac.kobe_u.cs.cream;

import jp.ac.kobe_u.cs.cream.*;
import java.util.*;

public class TabooSearch extends LocalSearch {
    public int tabooLength = 16;
    protected Operation taboo[] = null;
    protected int taboo_i;

    public TabooSearch(Network network) {
	this(network, DEFAULT, null);
    }

    public TabooSearch(Network network, int option) {
	this(network, option, null);
    }

    public TabooSearch(Network network, String name) {
	this(network, DEFAULT, name);
    }

    public TabooSearch(Network network, int option, String name) {
	super(network, option, name);
	setExchangeRate(0.8);
    }

    protected void clearTaboo() {
	taboo = new Operation[tabooLength];
	for (int i = 0; i < taboo.length; i++) {
	    taboo[i] = null;
	}
	taboo_i = 0;
    }

    protected boolean isTaboo(Operation op, Operation taboo[]) {
	if (taboo == null)
	    return false;
	for (int i = 0; i < taboo.length; i++) {
	    if (taboo[i] != null && op.isTaboo(taboo[i]))
		return true;
	}
	return false;
    }

    protected void addTaboo(Operation op) {
	taboo[taboo_i] = op;
	taboo_i = (taboo_i + 1) % taboo.length;
    }

    protected void startSearch() {
	clearTaboo();
	solver = new DefaultSolver(network, option);
	solution = solver.findFirst();
    }

    protected void nextSearch() {
	Operation locallyBestOp = null;
	Solution locallyBestSol = null;
	int locallyBest = IntDomain.MAX_VALUE;
	solution = candidate();
	Code code = solution.getCode();
	while (! isAborted()) {
	    Iterator ops = code.operations().iterator();
	    while (ops.hasNext() && ! isAborted()) {
		Operation op = (Operation)ops.next();
		if (isTaboo(op, taboo))
		    continue;
		code.setTo(network);
		op.applyTo(network);
		Solution sol = solver.findBest(iterationTimeout);
		if (sol == null)
		    continue;
		int value = sol.getObjectiveIntValue();
		if (! isBetter(value, locallyBest))
		    continue;
		locallyBest = value;
		locallyBestOp = op;
		locallyBestSol = sol;
	    }
	    if (locallyBestOp != null)
		break;
	    clearTaboo();
	}
	code.setTo(network);
	locallyBestOp.applyTo(network);
	solution = locallyBestSol;
	addTaboo(locallyBestOp);
    }
}
